package at.ac.univie.zsu.aguataplan.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import at.ac.univie.zsu.aguataplan.domain.Event;
import at.ac.univie.zsu.aguataplan.domain.EventAttribute;
import at.ac.univie.zsu.aguataplan.domain.EventAttributeValue;
import at.ac.univie.zsu.aguataplan.domain.EventAttributeValueString;
import at.ac.univie.zsu.aguataplan.exception.DatabaseException;

/**
 * @author gerry
 * 
 */
@Repository
public class EventDaoBean implements EventDao {
	@PersistenceContext
	transient EntityManager em;

	@Autowired
	private Dao dao;

	// ----------------------------------------------------
	// CONSTRUCTOR
	// ----------------------------------------------------

	public EventDaoBean() {

	}

	// ----------------------------------------------------
	// METHODS
	// ----------------------------------------------------

	@Override
	@Transactional
	public void cleanEventEventAttributeEventAttributeValueString() throws Exception {
		List<Event> events = dao.findAll(Event.class);
		List<EventAttribute> eventAttributes = dao.findAll(EventAttribute.class);
		List<EventAttributeValue> eventAttributeValueString = dao.findAll(EventAttributeValue.class);

		for (Event e : events) {
			deleteEvent(e.getId());
		}

		for (EventAttribute e : eventAttributes) {
			deleteEventAttribute(e.getId());
		}

		for (EventAttributeValue e : eventAttributeValueString) {
			deleteEventAttributeValueString(e.getId());
		}
	}

	// --------------

	@Override
	public Event addEvent(Event event) throws Exception {
		dao.persist(event);

		return event;
	}

	@Override
	public Event getEventById(long id) throws Exception {
		Event retEvent = null;
		retEvent = dao.find(Event.class, id);

		Hibernate.initialize(retEvent.getRefEventAttribute());

		return retEvent;
	}

	@Override
	public void deleteEvent(long id) throws Exception {
		dao.remove(Event.class, id);

	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Event> getEventList() throws Exception {
		List<Event> events;
		events = em.createQuery("SELECT o FROM " + Event.class.getName() + " o ORDER BY name").getResultList();

		return events;
	}

	@Override
	public Event mergeEvent(Event event) throws Exception {
		Event e;
		e = dao.merge(event);

		return e;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Event> getEventListNonEmpty() throws Exception {
		List<Event> events;
		events = em.createQuery(
				"FROM " + Event.class.getName()
						+ " AS event WHERE event.refEventAttribute.size > 0 ORDER BY event.name").getResultList();

		return events;
	}

	// --------------

	@Override
	public EventAttribute addEventAttribute(EventAttribute eventAttribute) throws Exception {
		dao.persist(eventAttribute);

		return eventAttribute;
	}

	@Override
	public EventAttribute getEventAttributeById(long id) throws Exception {
		EventAttribute retEventAttribute = null;
		retEventAttribute = dao.find(EventAttribute.class, id);

		Hibernate.initialize(retEventAttribute.getRefEvent());
		Hibernate.initialize(retEventAttribute.getRefEventAttributeValue());

		return retEventAttribute;
	}

	@Override
	public void deleteEventAttribute(long id) throws Exception {
		dao.remove(EventAttribute.class, id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EventAttribute> getEventAttributeList() throws Exception {
		List<EventAttribute> eventAttributes;
		eventAttributes = em.createQuery("SELECT o FROM " + EventAttribute.class.getName() + " o ORDER BY name")
				.getResultList();

		return eventAttributes;
	}

	@Override
	public EventAttribute mergeEventAttribute(EventAttribute eventAttribute) throws Exception {
		EventAttribute a;
		a = dao.merge(eventAttribute);

		return a;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EventAttribute> getEventAttributeListByEventNonEmpty(Event event) throws Exception {
		List<EventAttribute> list;
		String query = "SELECT eventAttribute FROM Event AS event RIGHT JOIN event.refEventAttribute AS eventAttribute WHERE event.id = "
				+ event.getId() + " AND eventAttribute.refEventAttributeValue.size > 0 ORDER BY eventAttribute.name";
		list = em.createQuery(query).getResultList();

		return list;
	}

	// --------------

	@Override
	public EventAttributeValueString addEventAttributeValueString(EventAttributeValueString eventAttributeValueString)
			throws Exception {
		dao.persist(eventAttributeValueString);

		return eventAttributeValueString;
	}

	@Override
	public EventAttributeValueString getEventAttributeValueStringById(long id) throws Exception {
		EventAttributeValueString retEventAttributeValueString;
		retEventAttributeValueString = dao.find(EventAttributeValueString.class, id);

		Hibernate.initialize(retEventAttributeValueString.getRefEventAttribute());

		return retEventAttributeValueString;
	}

	@Override
	public void deleteEventAttributeValueString(long id) throws Exception {
		dao.remove(EventAttributeValueString.class, id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EventAttributeValueString> getEventAttributeValueStringList() throws Exception {
		List<EventAttributeValueString> eventAttributeValueStrings;
		eventAttributeValueStrings = em.createQuery(
				"SELECT o FROM " + EventAttributeValueString.class.getName() + " o ORDER BY attValue").getResultList();

		return eventAttributeValueStrings;
	}

	@Override
	public EventAttributeValueString mergeEventAttributeValueString(EventAttributeValueString eventAttributeValueString)
			throws Exception {
		EventAttributeValueString a;
		a = dao.merge(eventAttributeValueString);

		return a;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EventAttributeValueString> getEventAttributeValueStringListByEventAttribute(
			EventAttribute eventAttribute) throws Exception {
		List<EventAttributeValueString> list;
		String query = "SELECT eventAttributeValueString FROM EventAttribute AS eventAttribute RIGHT JOIN eventAttribute.refEventAttributeValue AS eventAttributeValueString WHERE eventAttribute.id = "
				+ eventAttribute.getId() + " ORDER BY eventAttributeValueString.attValue";
		list = em.createQuery(query).getResultList();

		return list;
	}

	// --------------

	@Override
	@Transactional
	public void addEventEventAttribute(Event event, EventAttribute eventAttribute) throws Exception {
		// em.merge(event);
		// em.merge(eventAttribute);
		// em.flush();

		event.addEventAttribute(eventAttribute);

		Event e;
		EventAttribute ea;

		e = em.merge(event);

		ea = em.find(EventAttribute.class, eventAttribute.getId());
		ea.addEvent(e);
		em.merge(ea);

		em.flush();

	}

	@Override
	@Transactional
	public void addEventAttributeEventAttributeValueString(EventAttribute eventAttribute,
			EventAttributeValueString eventAttributeValueString) throws Exception {

		eventAttribute.addEventAttributeValueString(eventAttributeValueString);

		EventAttribute ea;
		EventAttributeValueString eavs;

		ea = em.merge(eventAttribute);

		eavs = em.find(EventAttributeValueString.class, eventAttributeValueString.getId());
		eavs.addEventAttribute(ea);
		em.merge(eavs);

		em.flush();
	}

	@Override
	@Transactional
	public void deleteEventEventAttribute(Event event, EventAttribute eventAttribute) throws Exception {

		// TODO: lookup is a linear lookup but not a hash
		if (!event.deleteEventAttribute(eventAttribute)) {
			throw new DatabaseException("could not save entry", "could not delete eventAttribute");
		}

		Event e;
		e = em.merge(event);

		EventAttribute ea;
		ea = em.find(EventAttribute.class, eventAttribute.getId());

		if (!ea.deleteEvent(e)) {
			throw new DatabaseException("could not save entry", "could not delete event");
		}
		em.merge(ea);

		em.flush();
	}

	@Override
	@Transactional
	public void deleteEventAttributeEventAttributeValueString(EventAttribute eventAttribute,
			EventAttributeValueString eventAttributeValueString) throws Exception {

		// TODO: lookup is a linear lookup but not a hash
		if (!eventAttribute.deleteEventAttributeValueString(eventAttributeValueString)) {
			throw new DatabaseException("could not save entry", "could not delete eventAttributeValueString");
		}

		EventAttribute ea;
		ea = em.merge(eventAttribute);

		EventAttributeValueString eavs;
		eavs = em.find(EventAttributeValueString.class, eventAttributeValueString.getId());

		if (!eavs.deleteEventAttribute(ea)) {
			throw new DatabaseException("could not save entry", "could not delete eventAttribute");
		}

		em.merge(eavs);
		em.flush();

	}

	// ----------------------------------------------------
	// GETTER & SETTER
	// ----------------------------------------------------

	public Dao getDao() {
		return dao;
	}

	public void setDao(Dao dao) {
		this.dao = dao;
	}

}
